package dmitrygusev.nanoxml;

import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import dmitrygusev.nanoxml.lite.XMLElement;

public class SimpleXPathService {

	@SuppressWarnings("unchecked")
	public static List<XMLElement> query(XMLElement element, String xpath) {
		List<XMLElement> result = new ArrayList<XMLElement>();
		
		if (xpath.startsWith("//")) {
			//	Try to apply XPath to every child xml element
			return visitRecursive(element, xpath.substring(2));
		}
		
		int indexOf = -1;
		String part = null;
		
		indexOf = xpath.indexOf('/');
		part = indexOf > 0 ? xpath.substring(0, indexOf) : xpath;
		
		//	Slash in attribute values
		while (indexOf != -1 && ( isSlashInAttributeValue(part) )) {
			indexOf = xpath.indexOf('/', indexOf + 1);
			part = indexOf > 0 ? xpath.substring(0, indexOf) : xpath;
		}
		
		boolean matches = true;
		
		if (part.contains("[@")) {
			//	Filter by attribute selector
			String attributeSelector = part.substring(part.indexOf("[@") + "[@".length(), part.length() - 1);
			
			matches = matches && isAttributeSelectorMatches(element, attributeSelector);
		}
		
		if (! part.startsWith("[@")){
			//	Filter by tag name selector
			
			String tagNameSelector = part.contains("[@") ? part.substring(0, part.indexOf("[@")) : part;
			
			matches = matches && element.getName().equals(tagNameSelector);
		}
		
		if (matches) {
			if (indexOf > 0) {
				//	Go to children
				for (XMLElement child : (Vector<XMLElement>) element.getChildren()) {
					result.addAll(query(child, xpath.substring(indexOf + "/".length())));
				}
			} else {
				result.add(element);
			}
		}
		
		return result;
	}

	private static boolean isSlashInAttributeValue(String part) {
		int quotCounter = 0;
		
		for (int i = 0; i < part.length(); i++) {
			if (part.charAt(i) == '\'' || part.charAt(i) == '"') {
				quotCounter++;
			}
		}
		return quotCounter % 2 != 0;
	}

	private static boolean isAttributeSelectorMatches(XMLElement element, String attributeSelector) {
		String[] nameValuePair = attributeSelector.split("=");
		String queryAttrName = nameValuePair[0].trim();
		String queryAttrValue = nameValuePair[1].trim();
		
		if ((queryAttrValue.startsWith("\"") && queryAttrValue.endsWith("\"")) ||
			(queryAttrValue.startsWith("'") && queryAttrValue.endsWith("'"))) {
			
			if (queryAttrValue.length() == 2) {
				queryAttrValue = "";
			} else {
				queryAttrValue = queryAttrValue.substring(1, queryAttrValue.length() - 1);				
			}
		}
		
		Object attrValue = element.getAttribute(queryAttrName, null);
		
		return queryAttrValue.equals(attrValue);
	}

	@SuppressWarnings("unchecked")
	private static List<XMLElement> visitRecursive(XMLElement element, String xpath) {
		List<XMLElement> result = new ArrayList<XMLElement>();
		
		result.addAll(query(element, xpath));
		
		if (result.size() > 0) {
			//	Don't go down
		}
		else {
			for (XMLElement child : (Vector<XMLElement>) element.getChildren()) {
				result.addAll(visitRecursive(child, xpath));
			}
		}
		
		return result;
	}
	
}
